#pragma once

#include "Log.hpp"
#include "Socket.hpp"
#include "functional"
#include <pthread.h>

class HttpServer;
class ThreadData
{
public:
    ThreadData(int sock, const std::string &ip, const uint16_t &port, HttpServer *ptr)
        : sock_(sock), clientip_(ip), clientPort_(port), current_(ptr)
    {
    }

public:
    int sock_;
    std::string clientip_;
    uint16_t clientPort_;
    HttpServer *current_;
};

class HttpServer
{
    using func_t = std::function<std::string(const std::string &)>;
    const static uint16_t defaultPort = 8888;

public:
    HttpServer(const func_t &func, const uint16_t port = defaultPort)
        : func_(func), port_(port)
    {
    }
    void Init()
    {
        listenSock_.createSocket();
        listenSock_.Bind(port_);
        listenSock_.Listen();
        LOG(DEBUG, "Init server success!");
    }
    void Start()
    {
        while (true)
        {
            uint16_t clientPort;
            std::string clientIp;
            int clientSock = listenSock_.Accept(&clientIp, &clientPort);
            if (clientSock == -1)
            {
                continue;
            }
            ThreadData *td = new ThreadData(clientSock, clientIp, clientPort, this);
            pthread_t pth;
            pthread_create(&pth, nullptr, threadRoutine, td);
        }
    }

    static void *threadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        std::string resquest = ReadRequest(td->sock_);
        /*char buff[4096];
        ssize_t bytes;
        while(bytes = recv(td->sock_,buff,sizeof(buff)-1,0)>0)
        {
            buff[bytes] = 0;
            resquest+=buff;
            if(resquest.find("\r\n\r\n")!=std::string::npos)
                break;
        }*/
        if (!resquest.empty())
        {
            std::string response = td->current_->func_(resquest);
            send(td->sock_, response.c_str(), response.size(), 0);
        }
        close(td->sock_);
        delete td;
        return nullptr;
    }
    static std::string ReadRequest(int sock)
    {
        std::string request;
        char buffer[1024];
        ssize_t bytes;
        while ((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0)
        {
            buffer[bytes] = '\0';
            request += buffer;
            if (request.find("\r\n\r\n") != std::string::npos) // HTTP 头部结束
                break;
        }
        return request;
    }

    ~HttpServer()
    {
        listenSock_.Close();
    }

private:
    yui::Socket listenSock_;
    func_t func_;
    uint16_t port_;
};